Last tutorial, we discovered the UserType class to give a more object oriented vibe to our scripting environments. However, we missed on some other functionalities that can be used next to them. In this tutorial, we will see :
Using these tools, the way to personalize our user types will take a new dimension !
Through this tutorial we will see many code snippets and witness their effects through the log of messages. To ease the reading, we will introduce specific blocks, to hold the log for :
They will take the form of :
Using this, we will avoid redundant images showing consoles in order to make the tutorial easier to read.
To put some context, we take back the last tutorial's code from where it was. Some reminders about the structure and the type creation :
For this tutorial, we added an internal array of 3 integers. This will be useful later.
Else, our C++ structure is only made by the fields from last tutorial. Then, our type was declared in the environment using :
For later demonstration, we also add two instances within the environment :
With this in mind, let's discover new functionalities !
Like in C++, user types give the ability to override operators, and to some extent, some built-in functions. Let's demonstrate what it's capable of with some code, by using overrideBuiltInFunction :
This function will take the type of built-in function / operator to overload. There are many available, from unary minus to string conversion. Best is to discover them through the API documentation of the enumeration class.
This function call returns a Function that we can populate. The function is already preset, with the parameters as being the operands involved, from left to right. For instance, in our case, first operand and second operand are fit within the data stack at indices 0 and 1. As such, what's left is to fill the function callback.
Our callback lambda just compares some fields and return the boolean result of that operation. Now, we can use it in our script :
The use of the "==" operator has been translated into a call to our now overloaded function. As simple as that !
To push further, remember the print method we had to declare last tutorial ? We can make it in a different fashion using this function :
We override the BUILT_IN_TO_STRING function this time, having only one operand, the object to convert. Doing this allows us to update our script to :
Overriding operators allows to align better with how they're used in C++, or help with using them within scripts as it can feel more natural.
Keep in mind some limits currently : operators take operands of the same type. It is currently not possible to mix a vector and a scalar for instance. You would need to make the scalar a vector with all members equal, and then you would be able to use it through this mechanism.
Accessing members of a class is usually done through a getter and a setter, which could be created through the method declaration functions. However, another elegant way of accessing public members is by declaring them as fields. To do so, we need a new include :
This descriptor class is used like this :
The descriptor has first to be created. It needs the name of the field to declare, along with its type, to drive the way the parameter stacks are type checked and filled.
Then, we can choose to use or not a getter and a setter. This depends on what operations you need to expose to the environment :
In our case, we simply change the values of our _i field. Now, to use it within a script :
Using the fields, we are able to change the way data can be accessed or written easily.
One last thing not exposed up til now is the way to index user types as arrays. You can see it like overloading the operator [] for our types. We need to include :
Then, like the field enabling function, we need to provide a descriptor of our access pattern :
First thing is to declare which type of variable we will expose through the array indexing. Here, we will expose integers.
We then give the callbacks to read / write. As with the fields, they can be provided or not, depending on the access you want to provide.
The array reading function takes a stack, that will be prefilled with the user data (0) and the index (1) requested. It is best to return the right type of data declared, here an integer.
To write, the function provides the user data (0), the index (1), and the value to assign (2). It doesn't take any return value.
Finally, we enable array indexing on the type itself using the descriptor. Then we can use it within the scripting environment :
The type is directly used as if it was an array, using the [] operator. This descriptor providing read and write functions, we can use both of them in the script.
To conclude, we discovered new ways of using the UserType class to :
All of these can be used to make scripts more intuitive to write.
And with this tutorial, we covered all available functionalities of the UserType class. Use them wisely !